Skip to content

refactor(cloud): thread probe identity explicitly instead of pinning process env#56

Merged
sourcehawk merged 3 commits into
feature/cloud-context-mcpfrom
feature/cloud-context-mcp--probe-thread
May 30, 2026
Merged

refactor(cloud): thread probe identity explicitly instead of pinning process env#56
sourcehawk merged 3 commits into
feature/cloud-context-mcpfrom
feature/cloud-context-mcp--probe-thread

Conversation

@sourcehawk
Copy link
Copy Markdown
Owner

Description

Towards #44

The launcher-side cloud identity probe pinned each provider's expected-identity env via process-global os.Setenv (serialized behind a mutex) because the providers read that env through os.Getenv in-process. Mutating process-global env from a request path is a concurrency footgun. This threads the pinned identity and the subprocess credential env explicitly instead, so concurrent probes for different sources never share state.

It is an internal threading refactor: the profile schema (CloudSource), the ProbeSource(ctx, Source) signature, and all launcher behavior are unchanged. The serve --kind=cloud subprocess still authenticates from its injected env.

Changes

  • Provider.Identity and cloud.Probe take the pinned identity (expected) and the subprocess env explicitly; the gcp and aws implementations validate the resolved identity against expected instead of reading their own os.Getenv.
  • ProbeSource no longer mutates the launcher process env (and drops the serializing mutex). It builds the subprocess credential env explicitly — base PATH/HOME plus the provider's declared config-dir passthrough names carried from os.Environ, with the source credential var overlaid — and threads the pinned identity into cloud.Probe.
  • A uniform TRIAGENT_CLOUD_EXPECTED_IDENTITY env carries the pinned identity for both providers, set by cloudSourceEnv alongside the per-provider credential env (gcp impersonation target, aws assume-role profile) and read once by runCloud in the serve subprocess. The aws-only expected-role-ARN env is removed.

Challenges

The serve subprocess and the launcher-side probe sit in different processes with different ambient env. The subprocess legitimately reads its injected credential env from os.Environ (via Server.subprocessEnv()), but the launcher process does not hold the pinned credential — which is why the old code mutated global env to fake it. The fix splits the env-building responsibility: the subprocess path keeps reading os.Environ, while ProbeSource constructs the credential env explicitly per source and passes it through cloud.Probe, so neither path mutates shared state.

Testing

make test-go is race-clean and green; make lint reports 0 issues. Added a test proving ProbeSource leaves the process env untouched (a sentinel, AWS_PROFILE, and the gcp impersonation env all read identically after probing both providers), a sourceEnvFor overlay test (source credential overrides the operator's ambient value; undeclared env never crosses the boundary), and a nil-provider contract-error test on Probe. The provider identity tests now thread expected directly instead of setting env. The existing harness_security_test.go minimal-env guarantees for run_cli are unaffected.

🤖 Generated with Claude Code

sourcehawk and others added 3 commits May 30, 2026 17:37
Provider.Identity and cloud.Probe now take the pinned identity and the
subprocess env explicitly instead of reading process-global env. The gcp and
aws Identity implementations validate the resolved identity against the threaded
expected value, dropping their os.Getenv reads. cloud.Server carries
ExpectedIdentity (read once from TRIAGENT_CLOUD_EXPECTED_IDENTITY in the serve
subprocess) and builds the probe env via subprocessEnv().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProbeSource no longer mutates the launcher's process env (and its serializing
mutex) to pin the per-provider expected identity. It now builds the subprocess
credential env explicitly — base PATH/HOME plus the provider's declared
config-dir passthrough names carried from os.Environ, with the source credential
var overlaid — and threads the pinned identity into cloud.Probe. A test pins the
no-mutation guarantee.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erve

cloudSourceEnv now sets the uniform TRIAGENT_CLOUD_EXPECTED_IDENTITY for both
providers in addition to the per-provider credential env the CLI authenticates
with (gcp impersonation target, aws assume-role profile), replacing the
aws-only expected-role-ARN env. runCloud reads the uniform env once and threads
it into cloud.Options.ExpectedIdentity.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sourcehawk sourcehawk merged commit a31ff0c into feature/cloud-context-mcp May 30, 2026
4 checks passed
@sourcehawk sourcehawk deleted the feature/cloud-context-mcp--probe-thread branch May 30, 2026 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant